#include "mmu/seg.h"
#include "mmu/mmu.h"

### 以下代码是 16 位模式
.code16
.globl start
start:
    # 关 cpu 中断
    cli

    # 各个段寄存器清零
    xorw    %ax,%ax
    movw    %ax,%ds
    movw    %ax,%es
    movw    %ax,%ss

    # 打开 A20 以支持访问 1MB 以上内存
seta20.1:
    inb     $0x64,%al
    testb   $0x2,%al
    jnz     seta20.1

    movb    $0xd1,%al
    outb    %al,$0x64

seta20.2:
    inb     $0x64,%al
    testb   $0x2,%al
    jnz     seta20.2

    movb    $0xdf,%al
    outb    %al,$0x60

    # 切换到 32 位模式
    lgdt    gdtdesc

    movl    %cr0, %eax     
    orl     $CR0_PE, %eax 
    movl    %eax, %cr0

    # 重新设置内核代码段选择子
    ljmp    $(SEG_KCODE << 3), $start32
### 16 位模式结束

### 以下代码是 32 位模式
.code32
start32:
    # 设置各个段选择子
    movw    $(SEG_KDATA << 3), %ax
    movw    %ax, %ds
    movw    %ax, %es
    movw    %ax, %ss
    movw    $0, %ax
    movw    %ax, %fs
    movw    %ax, %gs

    # 设置栈地址，跳转到 bootmain 执行
    movl    $start, %esp
    call    bootmain

spin:
    jmp     spin

### 启动用的 GDT 全局描述符表信息
.p2align 2
gdt: 
    SEG_NULLASM                             # 第一项固定为空
    SEG_ASM(STA_X | STA_R, 0x0, 0xffffffff) # 代码段可读可执行
    SEG_ASM(STA_W, 0x0, 0xffffffff)         # 数据段可写

gdtdesc:
    .word   (gdtdesc - gdt - 1)
    .long   gdt

### 16 位模式调试打印函数
#if 0
debug_msg:
    # 初始化段寄存器
    movw    %cs,%ax
    movw    %ax,%ds
    movw    %ax,%es
    movw    %ax,%ss

    # 初始化栈地址
    movw    $0x7c00,%sp

    # 清屏
    movw    $0x600,%ax
    movw    $0x700,%bx
    movw    $0,%cx
    movw    $0x184f,%dx
    int     $0x10

    # 输出信息 
    movw    $msg,%ax
    movw    %ax,%bp
    movw    $len,%cx
    movw    $0x1301,%ax
    movw    $0x2,%bx
    int     $0x10

    # 字符串信息 
    msg : .string " ACOINFO SB"
    len = . - msg
#endif